/*
 * Copyright (C) 2022 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef MODELMANAGER_P_H
#define MODELMANAGER_P_H

#include <QObject>
#include "modelmanager.h"
#include "configmanager.h"
#include "singleton.h"
#include "config.h"

class DesktopDataHandler;
class AppManager;
class TaskBarManager;
class ModelManagerPrivate : public QObject
{
    Q_DECLARE_PUBLIC(ModelManager)
public:
    ModelManagerPrivate(ModelManager *parent);
    enum ParentItemType {
        Page,
        Group,
    };
    struct PlaceholderItemInfo {
        LauncherItem *placeholderItem = nullptr;
        int itemIndex = -1;
        int pageIndex = -1;
        int groupId = -1;
        ParentItemType parentItemType;
    };

    void initTaskBarData(const QList<int> &ids,
                         const QMap<int, UKUI::BaseItem *> &itemData);

    LauncherItem* createItem(const int itemId, const int page);
    LauncherItem *createLauncherItem(LauncherItem::ItemType type,
                                     UKUI::BaseItem *srcItem,
                                     int page);

    ///
    /// \brief layoutForAddPlaceholderItem 如果添加 placeholder item 的页当前已经是满屏,
    ///  则需要将最后一个 item 移动到下一个屏幕,需要重新布局
    /// \param page 当前插入 placeholder item 的页
    /// \param groupId placeholder item 所在的分组 id,默认为 -1,即不在分组内
    ///
    void layoutForAddPlaceholderItem(int page, int groupId = -1);

    ///
    /// \brief layoutForRemovePlaceholderItem 删除 placeholder item 之后需要重新布局还原位置
    ///
    void layoutForRemovePlaceholderItem();

    ///
    /// \brief layoutForReplacePlaceholderItem 拖动 item 放至 placeholder item 之后,恢复由于插入
    ///  placeholder item 产生的布局变化
    ///
    void layoutForReplacePlaceholderItem();

    LauncherItem *createAddIconItem(int pageIndex, int state = LauncherItem::Normal);
    LauncherItem *createAppIcon(int itemId, int pageIndex);

    ///
    /// \brief createPage 创建新页
    /// \param pageIndex 页索引
    /// \param groupId 页所在的分组
    /// \param state 页的状态，默认为 LauncherItem::Editable
    /// \return 返回创建的页model
    ///
    PageModel *createPage(int pageIndex,
                          int groupId,
                          int state = LauncherItem::Editable);
    void tryAddAddIcon(int containerId);

    QPair<QString, QString> categoryIcon(int category);
    bool itemExistsInGroup(int groupId, int itemId);

    ///
    /// \brief itemGroupId 查找item所在的group的id
    /// \param itemId
    /// \return 如果item不在分组内则返回-1
    ///
    int itemGroupId(int itemId);
    QList<quint32> itemIdsInGroup(int groupId);

    void removeItemFromCategory(int itemId);
    int categoryOfAddtionPage(int page);

    QList<int> selectedIds() const;

    bool categoryContainsItem(int itemId, int category);

    ///
    /// \brief autoPushBackItemForGroup
    /// \param itemId
    /// \param groupId
    /// \param startPageIndex
    /// \return
    ///
    void autoPushBackItemForGroup(int itemId,
                                 int groupId,
                                 int startPageIndex);

    ///
    /// \brief updateCategoriesItemsPageIndex update the pageIndex of item in \memberof categoryItemsModel
    /// \param startPageIndex
    /// \param diff
    ///
    void updateCategoriesItemsPageIndex(int startPageIndex, int diff);

    void initSelectedItemIds(int groupId);

    ///
    /// \brief availableId 找到一个有效可用的id
    /// \return
    ///
    int availableId();

    LauncherItem *item(int itemId);

    ///
    /// \brief setItemNameVisible 设置分组内的item的名称是否可见
    /// \param model 分组的model
    /// \param visible bool
    ///
    void setItemNameVisible(MultiPageModel *model, bool visible);

    ///
    /// \brief replaceGroupWithAppIcon 当分组内只有一个应用时，用分组内的应用替换掉分组
    /// \param groupId
    ///
    void replaceGroupWithAppIcon(int groupId);

    bool groupIsEmpty(int groupId);

    int findTheSameNumber(const QList<int> &set1, const QList<int> &set2);

    bool placeholderAvailable();
    void clearPlaceholderItemInfo();

    ///
    /// \brief availableModel 根据groupId返回指定的model
    /// \param groupId 想要获取的分组model的id，获取主页的model时传-1
    /// \return 当groupId不为-1且未找到对应的分组model时返回nullptr
    ///
    MultiPageModel *availableModel(int groupId);

    ///
    /// \brief itemIndexIsValid 用于判断item对应的index和pageIndex是否合法
    /// \param itemIndex item在所在页的index
    /// \param pageIndex item所在页的indx
    /// \param model item所在的model
    /// \return 合法时返回true
    ///
    bool itemIndexIsValid(int itemIndex, int pageIndex, const MultiPageModel *model);
    bool itemIndexOfInsertTaskbarIsValid(const int itemIndex);
    bool pageIndexIsValid(int pageIndex, const MultiPageModel *model);

    ///
    /// \brief groupAddPage 分组创建新页
    /// \param groupId 分组的id
    /// \return
    ///
    void groupAddPage(int groupId);

    ///
    /// \brief removeEmptyPage 删除model的某一页后，它后面所有页的item的PageIndex要减1
    /// \param groupId 需要设置PageIndex的model
    /// \return
    ///
    void removeEmptyPage(MultiPageModel * const model);

    ///
    /// \brief findGroupPageIndexFromDesktop 通过groupId查找分组在桌面的pageIndex
    /// \param groupId 分组的groupId
    /// \return 分组在桌面的pageIndex
    ///
    int findGroupPageIndexFromDesktop(const int &groupId);

    ///
    /// \brief removeGroupFromDesktop 将分组从桌面删除
    /// \param groupId 分组的groupId
    ///
    void removeGroupFromDesktop(const int &groupId);

    ///
    /// \brief fillUpGroupEmptySpace 分组应用卸载，后一页应用向前补齐空位
    /// \param page 卸载的应用所在的page
    /// \param groupId
    ///
    void fillUpGroupEmptySpace(int page, int groupId);

    ///
    /// \brief getGroupState 获取分组当前的状态
    /// \param groupId 分组的groupId
    ///
    int getGroupState(const int &groupId);

    ///
    /// \brief gridCount 计算pageIndex页所占网格数
    /// \param groupId
    /// \param pageIndex
    /// \return
    ///
    int gridCount(const int &groupId, const int &pageIndex);

    ///
    /// \brief getAppWhiteList 获取应用白名单
    ///
    void getAppWhiteList();

    ///
    /// \brief isAppInTheWhiteList 应用是否在白名单内
    /// \param desktopname
    ///
    bool isAppInTheWhiteList(const QString &desktopname);

    int itemIndexWithPinnedToTaskBar(int findInsertPosIndex);
    void setItemsStateInHomeScreen(int state);
    void setItemsStateInTaskbar(int state);
    void setItemsStateInPopupedGroup(int groupId, int state);
    void addBlankPageToAllModels();
    void deleteBlankPageFromAllModels();
    // groupName, friendlyName
    std::tuple<QString, QString> createNewGroupName(LauncherItem *underItem, LauncherItem *aboveItem);
    MultiPageModel *createGroup(int groupId, const QString &groupName, LauncherItem *underItem);
    int removeAboveItem(int newGroupId, PageModel *newPageModel, LauncherItem *aboveItem);
    void updateItemStatusInGroupAfterGroupStateChanged(int groupId, int state);
    void iterateMultiPageModelWithItemCallBack(MultiPageModel *model, const std::function<void(LauncherItem *item)>&callBack);
    bool iterateMultiPageModelWithItemReturnCallBack(MultiPageModel *model, const std::function<bool(LauncherItem *item)>&callBack);
    void iterateMultiPageModelWithItemIndexCallBack(MultiPageModel *model,
                                                    const std::function<void(LauncherItem *item, int pageIndex, int itemIndex)>&callBack);

    QPair<int, int> itemPosInGroup(const int itemId, const int groupId);
    void takeAppIdFromDesktop(const int itemId, const int pageIndex);
    void takeAppIdFromGroup(const int itemId, const int groupId);
    void addPageToContainer(const int containerId);
    void removeEmptyPageFromContainer(const int containerId);
    LauncherItem* taskbarWindowOpenItem(const QString &desktopName);
    bool isContainerPageEmpty(const int containerId, const int pageIndex);
    void updateItemPageIndexAfterDeletePage(MultiPageModel *model, const int deletePageIndex);

    MultiPageModel launcherModel;
    QMap<int, MultiPageModel *> groupModel;

    // 保存每个分组的每一页可容纳的item的最大数量
    QMap<int, int> maxItemCountAllowedInPageOfGroup;
    const int kMaxItemCountInGroupPage = 16;
    PlaceholderItemInfo placeholderItemInfo;

    CategoryModel categoryModel;
    MultiPageModel categoryItemsModel;

    //
    int currentCategoryOfAddion;

    QList<int> currentSelectedIds;
    const int kTaskBarGroupId = 0;

    /// \todo 根据配置文件修改配置
    int pageItemMaxCount = 24;
    bool needAddIcon = false;
    const int pageItemMaxOfAddition = 28;
    ///

    // 由于 placeholder item 导致页面布局改变的页
    // 不包括当前放置 placeholder item 的页
    QStack<int> layoutChangedPages;

    int globalState = LauncherItem::Normal;

    int untitledGroupCount = 0;

    DesktopDataHandler *dataHandler;
    AppManager *appManager;
    TaskBarManager *taskBarManager;

    ConfigManager &confMgr = common::Singleton<ConfigManager>::GetInstance();

    ModelManager *q_ptr;
    QStringList m_appWhiteList;
};

#endif // MODELMANAGER_P_H
